package com.cnbm.modules.messagequeue.producter;

import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.UUID;

@Component
public class RabbitSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 确认消息 的回调监听接口，，用于确认消息是否被broker所收到。
     * */
    /*final ConfirmCallback confirmCallback1 = new ConfirmCallback() {
        @Override
        public void handle(long deliveryTag, boolean multiple) throws IOException {
            System.err.println("消息ACK :"+multiple+",correlationDataId"+deliveryTag);
        }
    };*/

    /**
     * 确认消息 的回调监听接口，，用于确认消息是否被broker所收到。
     * 当消息被broker 成功接收到 后 会调用这个方法
     * */
    final ConfirmCallback confirmCallback = new ConfirmCallback() {
        /**
         * 参数：
         *      CorrelationData  作为一个唯一标识（ 生产者 消费者 消息确认的唯一标识 ）
         *      b                broker是否落盘成功
         *      s                失败的一些异常信息会送
         * */
        @Override
        public void confirm(CorrelationData correlationData, boolean b, String s) {
            System.err.println("消息ACK :"+b+",correlationDataId"+correlationData);
        }
    };


    /**
     *  @Description 向rabbitmq中发送消息
     *  @Param
     *          message     具体的消息内容
     *          properties  额外的附加属性
     *  @Return void
     *  @Author caixiang
     *  @Date 2020/6/17 
     **/
    public void send(Object message, Map<String,Object> properties) throws Exception{
        MessageHeaders messageHeaders = new MessageHeaders(properties);
        //message的Object 传进来的可能就是 泛型。。createMessage会自动生成 deliveryTag
        Message<?> msg = MessageBuilder.createMessage(message,messageHeaders);

        //唯一标识
        CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());

        //设置确认 confirm
        rabbitTemplate.setConfirmCallback(confirmCallback);

        /**
         * 声明消息处理器  (这个消息处理器 是在 发给broker 之前执行的（就是对你要发送给mq 的消息 进行封装处理 和 上面的confirmCallback不同）。)
         * 这个对消息进行处理  可以设置一些参数   对消息进行一些定制化处理
         * 我们这里  来设置消息的编码  以及消息的过期时间
         * 因为在.net 以及其他版本过期时间不一致   这里的时间毫秒值 为字符串
         * */
        MessagePostProcessor mpp = new MessagePostProcessor(){
            //当发送消息到broker 成功 之后调用下面的方法。
            @Override
            public org.springframework.amqp.core.Message postProcessMessage(org.springframework.amqp.core.Message message) throws AmqpException {
                System.err.println("posted todo:"+message);
                //message.getMessageProperties()  下 可以进行各种 SET 属性
                return message;
            }
        };
        //发送端 要可以注重routingkey。。。因为exchange 要依据这个routingkey 把这条消息转发给队列。
//        rabbitTemplate.convertAndSend("exchange1",
//                "springboot.rabbit",
//                msg,
//                mpp,
//                cd
//        );
        rabbitTemplate.convertAndSend("exchange2",
                "qgs.rabbit",
                msg,
                mpp,
                cd
        );
    }
}
